import sys
import os
import threading
import time
import logging
import socket
import subprocess
import re
import queue
from datetime import datetime
import requests
import uiautomator2 as u2
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import TimeoutException, NoSuchElementException, WebDriverException

from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, 
                             QPushButton, QLabel, QTextEdit, QLineEdit, QCheckBox, QComboBox,
                             QGridLayout, QGroupBox, QFormLayout, QMessageBox, QMenu, QFrame,
                             QScrollArea, QSizePolicy)
from PyQt5.QtCore import Qt, QTimer, QThread, pyqtSignal, QObject, QMutex
from PyQt5.QtGui import QFont, QColor, QTextCursor, QCursor

# Настройка логирования
logging.basicConfig(
    level=logging.DEBUG,
    format='%(asctime)s - %(levelname)s - %(message)s',
    datefmt='%Y-%m-%d %H:%M:%S'
)

# Глобальные переменные
successful_attempts = 0
failed_attempts = 0
batch_success_count = 0
pause_event = threading.Event()
pause_event.set()
is_processing = False
error_attempt_counter = 0
auto_paused_due_to_wifi = False

# Счетчики для различных типов ошибок
invalid_login_count = 0
captcha_count = 0
token_not_found_count = 0
timeout_count = 0
element_not_found_count = 0
unexpected_error_count = 0

all_results = []
file_lock = threading.Lock()

# Пути к файлам
tokens_file = r"C:\Users\1\Desktop\VS 2022\Получение токенов ВК\tokens.txt"
failed_logins_file = r"C:\Users\1\Desktop\VS 2022\Получение токенов ВК\неуспешные логи.txt"
login_pass_file = r"C:\Users\1\Desktop\VS 2022\Получение токенов ВК\log pass.txt"
driver_path = r"C:\Users\1\Desktop\chromedriver_win64\chromedriver.exe"
last_limit_file = r"last limit.txt"
hide_browser_state_file = r"hide_browser_state.txt"
last_model_file = r"last_model.txt"
run_scenario_start_state_file = r"run_scenario_start_state.txt"
run_scenario_end_state_file = r"run_scenario_end_state.txt"
tokens_autoscroll_state_file = r"tokens_autoscroll_state.txt"
failed_autoscroll_state_file = r"failed_autoscroll_state.txt"

devices_by_model = {}
available_wifi_networks = []

# Функция для форматирования времени в формат ЧЧ:ММ:СС
def format_time(seconds):
    """Форматирует время из секунд в формат ЧЧ:ММ:СС"""
    hours = int(seconds // 3600)
    minutes = int((seconds % 3600) // 60)
    seconds = int(seconds % 60)
    return f"{hours:02d}:{minutes:02d}:{seconds:02d}"

# Сигналы для обновления GUI из потоков
class Signals(QObject):
    log_message = pyqtSignal(str, str)  # message, msg_type
    update_labels = pyqtSignal()
    append_token = pyqtSignal(str)
    append_failed_login = pyqtSignal(str, str)
    wifi_status_updated = pyqtSignal(str)
    ip_location_updated = pyqtSignal(str, str)
    device_scan_completed = pyqtSignal(list)
    wifi_scan_completed = pyqtSignal(list, str)

signals = Signals()

# Рабочий поток для обработки аккаунтов
class ProcessingThread(QThread):
    def __init__(self, main_window):
        super().__init__()
        self.main_window = main_window

    def run(self):
        global is_processing
        try:
            if self.main_window.run_scenario_start_check.isChecked():
                signals.log_message.emit("Запуск сценария в начале.", "info")
                self.main_window.run_flight_mode_scenario()
            self.process_all_accounts()
        except Exception as ex:
            signals.log_message.emit(f"Ошибка в основном потоке: {ex}", "error")
        finally:
            is_processing = False

    def process_all_accounts(self):
        accounts = read_login_passwords()
        for login, password in accounts:
            pause_event.wait()
            if not is_processing:
                break
            signals.log_message.emit(f"Обработка аккаунта: {login}", "info")
            self.main_window.open_browser(login, password)
        
        if is_processing and self.main_window.run_scenario_end_check.isChecked():
            signals.log_message.emit("Запуск сценария в конце.", "info")
            self.main_window.run_flight_mode_scenario()

class ClickableLabel(QLabel):
    """Кликабельная метка с подчёркиванием"""
    clicked = pyqtSignal()
    
    def __init__(self, text="", parent=None):
        super().__init__(text, parent)
        self.setCursor(QCursor(Qt.PointingHandCursor))
        self.setStyleSheet("""
            QLabel {
                color: #b8c0d0;
                text-decoration: underline;
                padding: 2px;
            }
            QLabel:hover {
                color: #ffffff;
                background-color: rgba(62, 70, 86, 0.3);
                border-radius: 2px;
            }
        """)
    
    def mousePressEvent(self, event):
        if event.button() == Qt.LeftButton:
            self.clicked.emit()
        super().mousePressEvent(event)

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.processing_thread = None
        self.timer_start_time = None
        self.total_elapsed_time = 0
        self.is_timer_running = False
        
        # Переменные для автопрокрутки
        self.tokens_autoscroll_enabled = True
        self.failed_autoscroll_enabled = True
        
        self.init_ui()
        self.center_window()  # Центрирование окна
        self.setup_timers()
        self.connect_signals()
        self.load_settings()
        self.setup_context_menus()
        
    def center_window(self):
        """Центрирование окна на экране"""
        # Получаем геометрию экрана
        screen_geometry = QApplication.desktop().availableGeometry()
        screen_center_x = screen_geometry.width() // 2
        screen_center_y = screen_geometry.height() // 2
        
        # Размеры окна
        window_width = 1200
        window_height = 950
        
        # Устанавливаем размер окна
        self.resize(window_width, window_height)
        
        # Вычисляем координаты для центрирования
        x = screen_center_x - window_width // 2
        y = screen_center_y - window_height // 2
        
        # Перемещаем окно в центр
        self.move(x, y)
        
    def init_ui(self):
        self.setWindowTitle("Получение токенов ВК (PyQt5)")
        self.setStyleSheet("""
            QMainWindow {
                background-color: #1e222a;
                color: #b8c0d0;
            }
            QGroupBox {
                font-weight: bold;
                border: 2px solid #3e4656;
                border-radius: 5px;
                margin-top: 1ex;
                padding-top: 10px;
                background-color: #262a33;
                color: #b8c0d0;
            }
            QGroupBox::title {
                subcontrol-origin: margin;
                left: 10px;
                padding: 0 5px 0 5px;
            }
            QPushButton {
                background-color: #3e4656;
                color: #b8c0d0;
                border: 1px solid #4e566a;
                padding: 8px;
                border-radius: 4px;
                font: 10pt "Segoe UI";
            }
            QPushButton:hover {
                background-color: #4e566a;
            }
            QPushButton:pressed {
                background-color: #2a2f38;
            }
            QPushButton:disabled {
                background-color: #2a2f38;
                color: #6b7280;
            }
            QLineEdit, QComboBox {
                background-color: #2a2f38;
                color: #b8c0d0;
                border: 1px solid #3e4656;
                padding: 5px;
                border-radius: 3px;
            }
            QTextEdit {
                background-color: #2a2f38;
                color: #b8c0d0;
                border: 1px solid #3e4656;
                border-radius: 3px;
            }
            QCheckBox {
                color: #b8c0d0;
            }
            QLabel {
                color: #b8c0d0;
            }
        """)
        
        central_widget = QWidget()
        self.setCentralWidget(central_widget)
        
        main_layout = QVBoxLayout(central_widget)
        main_layout.setSpacing(10)
        main_layout.setContentsMargins(10, 10, 10, 10)
        
        # Панель управления
        self.create_control_panel(main_layout)
        
        # Статистика
        self.create_status_panel(main_layout)
        
        # Логи
        self.create_logs_panel(main_layout)
        
    def create_control_panel(self, parent_layout):
        control_group = QGroupBox("Панель управления")
        control_layout = QVBoxLayout(control_group)
        
        # Первая строка кнопок
        row1_layout = QHBoxLayout()
        
        self.start_button = QPushButton("Запустить")
        self.start_button.setStyleSheet("QPushButton { background-color: #5b9bd5; }")
        self.start_button.clicked.connect(self.start_browser_thread)
        row1_layout.addWidget(self.start_button)
        
        self.pause_button = QPushButton("Приостановить")
        self.pause_button.setEnabled(False)
        self.pause_button.clicked.connect(self.pause_processing)
        row1_layout.addWidget(self.pause_button)
        
        self.resume_button = QPushButton("Восстановить")
        self.resume_button.setEnabled(False)
        self.resume_button.clicked.connect(self.resume_processing)
        row1_layout.addWidget(self.resume_button)
        
        self.restart_button = QPushButton("Перезапустить ошибки")
        self.restart_button.clicked.connect(self.restart_failed_accounts)
        row1_layout.addWidget(self.restart_button)
        
        self.update_labels_button = QPushButton("Обновить метки")
        self.update_labels_button.clicked.connect(self.update_status_labels)
        row1_layout.addWidget(self.update_labels_button)
        
        self.clear_logs_button = QPushButton("Очистить все журналы")
        self.clear_logs_button.clicked.connect(self.clear_all_logs)
        row1_layout.addWidget(self.clear_logs_button)
        
        row1_layout.addStretch()
        control_layout.addLayout(row1_layout)
        
        # Вторая строка - чекбоксы
        row2_layout = QHBoxLayout()
        
        self.hide_browser_check = QCheckBox("Скрыть браузер")
        row2_layout.addWidget(self.hide_browser_check)
        
        self.run_scenario_start_check = QCheckBox("Запустить сценарий в начале")
        row2_layout.addWidget(self.run_scenario_start_check)
        
        self.run_scenario_end_check = QCheckBox("Запустить сценарий в конце")
        row2_layout.addWidget(self.run_scenario_end_check)
        
        # Лимит токенов
        limit_label = QLabel("Лимит токенов:")
        row2_layout.addWidget(limit_label)
        
        self.limit_entry = QLineEdit()
        self.limit_entry.setMaximumWidth(60)
        self.limit_entry.setText("0")
        row2_layout.addWidget(self.limit_entry)
        
        row2_layout.addStretch()
        control_layout.addLayout(row2_layout)
        
        # Третья строка - устройства и Wi-Fi
        row3_layout = QHBoxLayout()
        
        self.device_combobox = QComboBox()
        self.device_combobox.addItem("Нет подключённых устройств")
        self.device_combobox.currentTextChanged.connect(self.on_model_selected)
        row3_layout.addWidget(self.device_combobox)
        
        self.scan_devices_button = QPushButton("Сканировать устройства")
        self.scan_devices_button.clicked.connect(self.scan_devices_async)
        row3_layout.addWidget(self.scan_devices_button)
        
        wifi_label = QLabel("Выбрать Wi-Fi:")
        row3_layout.addWidget(wifi_label)
        
        self.wifi_combobox = QComboBox()
        self.wifi_combobox.currentTextChanged.connect(self.on_wifi_selected)
        row3_layout.addWidget(self.wifi_combobox)
        
        self.refresh_wifi_button = QPushButton("Обновить Wi-Fi")
        self.refresh_wifi_button.clicked.connect(self.refresh_wifi_async)
        row3_layout.addWidget(self.refresh_wifi_button)
        
        row3_layout.addStretch()
        control_layout.addLayout(row3_layout)
        
        parent_layout.addWidget(control_group)
        
    def create_status_panel(self, parent_layout):
        status_group = QGroupBox("Статус")
        status_layout = QVBoxLayout(status_group)
        
        # Основная статистика
        stats_layout = QHBoxLayout()
        
        # Используем ClickableLabel для кликабельных меток
        self.success_label = ClickableLabel("Успешные попытки: 0")
        self.success_label.setStyleSheet("""
            QLabel {
                color: #89ca78;
                text-decoration: underline;
                padding: 2px;
            }
            QLabel:hover {
                color: #a4d9a0;
                background-color: rgba(137, 202, 120, 0.2);
                border-radius: 2px;
            }
        """)
        self.success_label.clicked.connect(self.copy_successful_tokens)
        stats_layout.addWidget(self.success_label)
        
        self.failure_label = ClickableLabel("Неуспешные попытки: 0")
        self.failure_label.setStyleSheet("""
            QLabel {
                color: #e57373;
                text-decoration: underline;
                padding: 2px;
            }
            QLabel:hover {
                color: #ffaaaa;
                background-color: rgba(229, 115, 115, 0.2);
                border-radius: 2px;
            }
        """)
        self.failure_label.clicked.connect(self.copy_failed_logins)
        stats_layout.addWidget(self.failure_label)
        
        self.count_label = QLabel("Всего аккаунтов: 0")
        self.count_label.setStyleSheet("color: #5b9bd5;")
        stats_layout.addWidget(self.count_label)
        
        self.remaining_label = QLabel("Оставшиеся аккаунты: 0")
        self.remaining_label.setStyleSheet("color: #f4a261;")
        stats_layout.addWidget(self.remaining_label)
        
        copy_all_label = ClickableLabel("Copy all")
        copy_all_label.setStyleSheet("""
            QLabel {
                color: #b8c0d0;
                text-decoration: underline;
                padding: 2px;
            }
            QLabel:hover {
                color: #ffffff;
                background-color: rgba(184, 192, 208, 0.2);
                border-radius: 2px;
            }
        """)
        copy_all_label.clicked.connect(self.copy_all)
        stats_layout.addWidget(copy_all_label)
        
        copy_successful_label = ClickableLabel("Copy successful")
        copy_successful_label.setStyleSheet("""
            QLabel {
                color: #89ca78;
                text-decoration: underline;
                padding: 2px;
            }
            QLabel:hover {
                color: #a4d9a0;
                background-color: rgba(137, 202, 120, 0.2);
                border-radius: 2px;
            }
        """)
        copy_successful_label.clicked.connect(self.copy_successful_only)
        stats_layout.addWidget(copy_successful_label)
        
        stats_layout.addStretch()
        status_layout.addLayout(stats_layout)
        
        # Счетчики ошибок - первая строка
        error_layout1 = QHBoxLayout()
        
        self.invalid_login_label = QLabel("Невалидный логин/пароль: 0")
        self.invalid_login_label.setStyleSheet("color: #ff6b6b; font-size: 9pt;")
        error_layout1.addWidget(self.invalid_login_label)
        
        self.captcha_label = QLabel("Капча: 0")
        self.captcha_label.setStyleSheet("color: #ff9f43; font-size: 9pt;")
        error_layout1.addWidget(self.captcha_label)
        
        self.token_not_found_label = QLabel("Токен не найден: 0")
        self.token_not_found_label.setStyleSheet("color: #feca57; font-size: 9pt;")
        error_layout1.addWidget(self.token_not_found_label)
        
        error_layout1.addStretch()
        status_layout.addLayout(error_layout1)
        
        # Счетчики ошибок - вторая строка
        error_layout2 = QHBoxLayout()
        
        self.timeout_label = QLabel("Timeout: 0")
        self.timeout_label.setStyleSheet("color: #ff7675; font-size: 9pt;")
        error_layout2.addWidget(self.timeout_label)
        
        self.element_not_found_label = QLabel("Элемент не найден: 0")
        self.element_not_found_label.setStyleSheet("color: #a29bfe; font-size: 9pt;")
        error_layout2.addWidget(self.element_not_found_label)
        
        self.unexpected_error_label = QLabel("Неожиданные ошибки: 0")
        self.unexpected_error_label.setStyleSheet("color: #fd79a8; font-size: 9pt;")
        error_layout2.addWidget(self.unexpected_error_label)
        
        error_layout2.addStretch()
        status_layout.addLayout(error_layout2)
        
        # Дополнительная информация
        info_layout = QHBoxLayout()
        
        self.total_time_label = QLabel("Общее время: 00:00:00")
        self.total_time_label.setStyleSheet("color: #f4a261;")
        info_layout.addWidget(self.total_time_label)
        
        self.wifi_status_label = QLabel("Подключенный Wi-Fi: Неизвестно")
        self.wifi_status_label.setStyleSheet("color: #bb77d1;")
        info_layout.addWidget(self.wifi_status_label)
        
        self.ip_label = QLabel("IP: Сканирование...")
        info_layout.addWidget(self.ip_label)
        
        self.location_label = QLabel("Локация: Сканирование...")
        info_layout.addWidget(self.location_label)
        
        info_layout.addStretch()
        status_layout.addLayout(info_layout)
        
        parent_layout.addWidget(status_group)
        
    def create_logs_panel(self, parent_layout):
        logs_layout = QHBoxLayout()
        
        # Журнал действий
        log_group = QGroupBox("Журнал действий")
        log_layout = QVBoxLayout(log_group)
        
        self.log_text = QTextEdit()
        self.log_text.setReadOnly(True)
        self.log_text.setMinimumHeight(300)
        log_layout.addWidget(self.log_text)
        logs_layout.addWidget(log_group)
        
        # Успешные токены
        tokens_group = QGroupBox("Успешные токены")
        tokens_layout = QVBoxLayout(tokens_group)
        
        self.successful_tokens_text = QTextEdit()
        self.successful_tokens_text.setReadOnly(True)
        self.successful_tokens_text.setMinimumHeight(300)
        tokens_layout.addWidget(self.successful_tokens_text)
        logs_layout.addWidget(tokens_group)
        
        parent_layout.addLayout(logs_layout)
        
        # Неуспешные логины
        failed_group = QGroupBox("Неуспешные логины и пароли")
        failed_layout = QVBoxLayout(failed_group)
        
        self.failed_logins_text = QTextEdit()
        self.failed_logins_text.setReadOnly(True)
        self.failed_logins_text.setMaximumHeight(150)
        failed_layout.addWidget(self.failed_logins_text)
        
        parent_layout.addWidget(failed_group)
        
    def setup_timers(self):
        # Таймер для обновления времени работы
        self.runtime_timer = QTimer()
        self.runtime_timer.timeout.connect(self.update_runtime_display)
        
        # Таймер для проверки Wi-Fi
        self.wifi_timer = QTimer()
        self.wifi_timer.timeout.connect(self.update_wifi_status)
        self.wifi_timer.start(2000)  # Каждые 2 секунды
        
        # Таймер для обновления IP и локации
        self.ip_timer = QTimer()
        self.ip_timer.timeout.connect(self.update_ip_location_display)
        self.ip_timer.start(15000)  # Каждые 15 секунд
        
    def setup_context_menus(self):
        # Контекстное меню для логов
        self.log_text.setContextMenuPolicy(Qt.CustomContextMenu)
        self.log_text.customContextMenuRequested.connect(self.show_log_context_menu)
        
        self.successful_tokens_text.setContextMenuPolicy(Qt.CustomContextMenu)
        self.successful_tokens_text.customContextMenuRequested.connect(self.show_tokens_context_menu)
        
        self.failed_logins_text.setContextMenuPolicy(Qt.CustomContextMenu)
        self.failed_logins_text.customContextMenuRequested.connect(self.show_failed_context_menu)
        
    def connect_signals(self):
        signals.log_message.connect(self.log_message)
        signals.update_labels.connect(self.update_status_labels)
        signals.append_token.connect(self.append_token)
        signals.append_failed_login.connect(self.append_failed_login)
        signals.wifi_status_updated.connect(self.wifi_status_label.setText)
        signals.ip_location_updated.connect(self.update_ip_location_labels)
        signals.device_scan_completed.connect(self.update_device_list)
        signals.wifi_scan_completed.connect(self.update_wifi_list)
        
    def load_settings(self):
        # Загрузка сохраненных настроек
        self.hide_browser_check.setChecked(self.load_hide_browser_state())
        self.run_scenario_start_check.setChecked(self.load_run_scenario_start_state())
        self.run_scenario_end_check.setChecked(self.load_run_scenario_end_state())
        self.limit_entry.setText(self.load_last_limit())
        
        # Загрузка состояния автопрокрутки
        self.tokens_autoscroll_enabled = self.load_tokens_autoscroll_state()
        self.failed_autoscroll_enabled = self.load_failed_autoscroll_state()
        
        # Инициализация
        self.log_message("Журнал действий:", "info")
        self.update_status_labels()
        self.scan_devices_async()
        self.refresh_wifi_async()
        self.update_ip_location_display()
        
    def log_message(self, message, msg_type="info"):
        timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        full_message = f"[{timestamp}] {message}"
        
        cursor = self.log_text.textCursor()
        cursor.movePosition(QTextCursor.End)
        self.log_text.setTextCursor(cursor)
        
        if msg_type == "info":
            self.log_text.setTextColor(QColor("#b8c0d0"))
        elif msg_type == "success":
            self.log_text.setTextColor(QColor("#89ca78"))
        elif msg_type == "error":
            self.log_text.setTextColor(QColor("#e57373"))
        
        self.log_text.insertPlainText(full_message + "\n")
        self.log_text.ensureCursorVisible()
        
    def append_token(self, token):
        self.successful_tokens_text.append(token)
        if self.tokens_autoscroll_enabled:
            self.successful_tokens_text.ensureCursorVisible()
        
    def append_failed_login(self, login, password):
        self.failed_logins_text.append(f"{login}:{password}")
        if self.failed_autoscroll_enabled:
            self.failed_logins_text.ensureCursorVisible()
        
    def update_status_labels(self):
        accounts = read_login_passwords()
        total_accounts = len(accounts)
        remaining = total_accounts - (successful_attempts + failed_attempts)
        
        self.success_label.setText(f"Успешные попытки: {successful_attempts}")
        self.failure_label.setText(f"Неуспешные попытки: {failed_attempts}")
        self.count_label.setText(f"Всего аккаунтов: {total_accounts}")
        self.remaining_label.setText(f"Оставшиеся аккаунты: {remaining}")
        
        # Обновляем счетчики ошибок
        self.invalid_login_label.setText(f"Невалидный логин/пароль: {invalid_login_count}")
        self.captcha_label.setText(f"Капча: {captcha_count}")
        self.token_not_found_label.setText(f"Токен не найден: {token_not_found_count}")
        self.timeout_label.setText(f"Timeout: {timeout_count}")
        self.element_not_found_label.setText(f"Элемент не найден: {element_not_found_count}")
        self.unexpected_error_label.setText(f"Неожиданные ошибки: {unexpected_error_count}")
        
    def start_browser_thread(self):
        global is_processing
        if is_processing:
            QMessageBox.information(self, "Информация", "Процесс уже запущен.")
            return
            
        add_token_separator()
        
        if self.wifi_combobox.currentText() != get_connected_wifi():
            QMessageBox.warning(self, "Внимание", 
                               "Текущая Wi-Fi сеть не совпадает с выбранной.\nЗапуск невозможен.")
            return
            
        self.save_last_limit()
        is_processing = True
        pause_event.set()
        
        self.start_button.setEnabled(False)
        self.pause_button.setEnabled(True)
        self.resume_button.setEnabled(False)
        
        # Запуск таймера
        self.start_timer()
        
        # Запуск обработки в отдельном потоке
        self.processing_thread = ProcessingThread(self)
        self.processing_thread.finished.connect(self.on_processing_finished)
        self.processing_thread.start()
        
    def pause_processing(self):
        global auto_paused_due_to_wifi
        if not is_processing:
            return
        pause_event.clear()
        auto_paused_due_to_wifi = False
        self.log_message("Процесс приостановлен (вручную).", "info")
        self.pause_button.setEnabled(False)
        self.resume_button.setEnabled(True)
        self.stop_timer()
        
    def resume_processing(self):
        if not is_processing:
            return
        if self.wifi_combobox.currentText() != get_connected_wifi():
            QMessageBox.warning(self, "Внимание", 
                               "Невозможно возобновить: текущая Wi-Fi сеть не совпадает с выбранной.")
            return
        pause_event.set()
        self.log_message("Процесс восстановлен (вручную).", "info")
        self.pause_button.setEnabled(True)
        self.resume_button.setEnabled(False)
        self.start_timer()
        
    def on_processing_finished(self):
        global is_processing
        is_processing = False
        self.start_button.setEnabled(True)
        self.pause_button.setEnabled(False)
        self.resume_button.setEnabled(False)
        self.stop_timer()
        
    def restart_failed_accounts(self):
        global successful_attempts, failed_attempts, batch_success_count
        global invalid_login_count, captcha_count, token_not_found_count
        global timeout_count, element_not_found_count, unexpected_error_count
        
        # Сброс всех счетчиков
        successful_attempts = 0
        failed_attempts = 0
        batch_success_count = 0
        invalid_login_count = 0
        captcha_count = 0
        token_not_found_count = 0
        timeout_count = 0
        element_not_found_count = 0
        unexpected_error_count = 0
        
        all_results.clear()
        self.update_status_labels()
        self.successful_tokens_text.clear()
        
        content = self.failed_logins_text.toPlainText().strip()
        if not content:
            QMessageBox.information(self, "Информация", "Нет аккаунтов для перезапуска.")
            return
            
        self.failed_logins_text.clear()
        
        try:
            with open(failed_logins_file, "w", encoding="utf-8") as f:
                f.write("")
        except Exception as e:
            self.log_message(f"Ошибка при очистке файла неуспешных логинов: {e}", "error")
            
        def process_failed():
            lines = content.splitlines()
            for line in lines:
                parts = line.split(":", 1)
                if len(parts) == 2:
                    login, password = parts
                    self.log_message(f"Перезапуск аккаунта: {login}", "info")
                    self.open_browser(login, password)
            signals.update_labels.emit()
            
        thread = threading.Thread(target=process_failed, daemon=True)
        thread.start()
        
    def clear_all_logs(self):
        reply = QMessageBox.question(self, "Подтверждение", 
                                   "Вы уверены, что хотите очистить журналы в интерфейсе?\n(Файлы tokens.txt и неуспешные логи.txt не будут затронуты)",
                                   QMessageBox.Yes | QMessageBox.No)
        if reply == QMessageBox.Yes:
            try:
                # Убрана строка очистки файла failed_logins_file
                # open(failed_logins_file, "w", encoding='utf-8').close()
            
                self.log_text.clear()
                self.successful_tokens_text.clear()
                self.failed_logins_text.clear()
            
                global successful_attempts, failed_attempts
                global invalid_login_count, captcha_count, token_not_found_count
                global timeout_count, element_not_found_count, unexpected_error_count
            
                successful_attempts = 0
                failed_attempts = 0
                invalid_login_count = 0
                captcha_count = 0
                token_not_found_count = 0
                timeout_count = 0
                element_not_found_count = 0
                unexpected_error_count = 0
            
                all_results.clear()
                self.update_status_labels()
                self.log_message("Журналы интерфейса очищены (файлы tokens.txt и неуспешные логи.txt сохранены).", "info")
            except Exception as e:
                QMessageBox.critical(self, "Ошибка", f"Не удалось очистить журналы: {e}")
        
    def copy_successful_tokens(self):
        content = self.successful_tokens_text.toPlainText().strip()
        if not content:
            QMessageBox.information(self, "Информация", "Нет токенов для копирования.")
            return
        QApplication.clipboard().setText(content)
        self.log_message("Токены скопированы в буфер обмена.", "info")
        
    def copy_failed_logins(self):
        content = self.failed_logins_text.toPlainText().strip()
        if not content:
            QMessageBox.information(self, "Информация", "Нет неуспешных логинов для копирования.")
            return
        QApplication.clipboard().setText(content)
        self.log_message("Неуспешные логины и пароли скопированы в буфер обмена.", "info")
        
    def copy_all(self):
        if not all_results:
            QMessageBox.information(self, "Информация", "Нет данных для копирования.")
            return
        lines = [f"{login}:{password}\t{result}" for login, password, result in all_results]
        text = "\n".join(lines)
        QApplication.clipboard().setText(text)
        self.log_message("Список логин:пароль и результатов скопирован.", "info")
        
    def copy_successful_only(self):
        if not all_results:
            QMessageBox.information(self, "Информация", "Нет данных для копирования.")
            return
            
        error_keywords = [
            "Невалидный логин или пароль",
            "Найдена капча", 
            "Токен не найден",
            "Timeout",
            "Элемент не найден",
            "Ошибка:",
            "Неожиданная ошибка",
            "Неизвестная ошибка"
        ]
        
        successful_results = []
        for login, password, result in all_results:
            is_error = any(keyword in result for keyword in error_keywords)
            if not is_error and len(result) > 10:
                successful_results.append((login, password, result))
                
        if not successful_results:
            QMessageBox.information(self, "Информация", "Нет успешных результатов для копирования.")
            return
            
        lines = [f"{login}:{password}\t{result}" for login, password, result in successful_results]
        text = "\n".join(lines)
        QApplication.clipboard().setText(text)
        self.log_message(f"Скопировано {len(successful_results)} успешных результатов в буфер обмена.", "info")
        
    def show_log_context_menu(self, pos):
        menu = QMenu()
        copy_action = menu.addAction("Копировать")
        select_all_action = menu.addAction("Выбрать всё")
        menu.addSeparator()
        autoscroll_action = menu.addAction("Автопрокрутка")
        autoscroll_action.setCheckable(True)
        autoscroll_action.setChecked(True)
        
        action = menu.exec_(self.log_text.mapToGlobal(pos))
        if action == copy_action:
            cursor = self.log_text.textCursor()
            if cursor.hasSelection():
                QApplication.clipboard().setText(cursor.selectedText())
        elif action == select_all_action:
            self.log_text.selectAll()
            
    def show_tokens_context_menu(self, pos):
        menu = QMenu()
        copy_action = menu.addAction("Копировать")
        select_all_action = menu.addAction("Выбрать всё")
        menu.addSeparator()
        autoscroll_action = menu.addAction("Автопрокрутка")
        autoscroll_action.setCheckable(True)
        autoscroll_action.setChecked(self.tokens_autoscroll_enabled)
        
        action = menu.exec_(self.successful_tokens_text.mapToGlobal(pos))
        if action == copy_action:
            cursor = self.successful_tokens_text.textCursor()
            if cursor.hasSelection():
                QApplication.clipboard().setText(cursor.selectedText())
        elif action == select_all_action:
            self.successful_tokens_text.selectAll()
        elif action == autoscroll_action:
            self.tokens_autoscroll_enabled = not self.tokens_autoscroll_enabled
            self.save_tokens_autoscroll_state()
            if self.tokens_autoscroll_enabled:
                self.log_message("Автопрокрутка для токенов включена.", "info")
            else:
                self.log_message("Автопрокрутка для токенов отключена.", "info")
                
    def show_failed_context_menu(self, pos):
        menu = QMenu()
        copy_action = menu.addAction("Копировать")
        select_all_action = menu.addAction("Выбрать всё")
        menu.addSeparator()
        autoscroll_action = menu.addAction("Автопрокрутка")
        autoscroll_action.setCheckable(True)
        autoscroll_action.setChecked(self.failed_autoscroll_enabled)
        
        action = menu.exec_(self.failed_logins_text.mapToGlobal(pos))
        if action == copy_action:
            cursor = self.failed_logins_text.textCursor()
            if cursor.hasSelection():
                QApplication.clipboard().setText(cursor.selectedText())
        elif action == select_all_action:
            self.failed_logins_text.selectAll()
        elif action == autoscroll_action:
            self.failed_autoscroll_enabled = not self.failed_autoscroll_enabled
            self.save_failed_autoscroll_state()
            if self.failed_autoscroll_enabled:
                self.log_message("Автопрокрутка для неуспешных логинов включена.", "info")
            else:
                self.log_message("Автопрокрутка для неуспешных логинов отключена.", "info")
            
    def start_timer(self):
        self.timer_start_time = time.time()
        self.is_timer_running = True
        self.runtime_timer.start(1000)  # Обновление каждую секунду
        
    def stop_timer(self):
        if self.is_timer_running and self.timer_start_time:
            self.total_elapsed_time += time.time() - self.timer_start_time
            self.is_timer_running = False
            self.runtime_timer.stop()
            
    def update_runtime_display(self):
        """Обновление отображения времени в формате ЧЧ:ММ:СС"""
        if self.is_timer_running and self.timer_start_time:
            current_time = self.total_elapsed_time + (time.time() - self.timer_start_time)
            formatted_time = format_time(current_time)
            self.total_time_label.setText(f"Время выполнения: {formatted_time}")
        else:
            formatted_time = format_time(self.total_elapsed_time)
            self.total_time_label.setText(f"Общее время: {formatted_time}")
            
    def update_wifi_status(self):
        current_wifi = get_connected_wifi()
        self.wifi_status_label.setText(f"Подключенный Wi-Fi: {current_wifi}")
        
        # Логика автопаузы при смене Wi-Fi
        selected_wifi = self.wifi_combobox.currentText()
        global auto_paused_due_to_wifi
        
        if selected_wifi and selected_wifi != current_wifi:
            if is_processing and pause_event.is_set():
                pause_event.clear()
                auto_paused_due_to_wifi = True
                self.log_message("Процесс приостановлен автоматически (Wi-Fi mismatch).", "info")
            if not is_processing:
                self.start_button.setEnabled(False)
        else:
            if not is_processing:
                self.start_button.setEnabled(True)
            else:
                if auto_paused_due_to_wifi and not pause_event.is_set():
                    pause_event.set()
                    auto_paused_due_to_wifi = False
                    self.log_message("Процесс возобновлён автоматически (Wi-Fi соответствует).", "info")
                    
    def update_ip_location_display(self):
        def worker():
            ip = get_external_ip()
            if ip != "Недоступно":
                location = get_location_by_ip(ip)
            else:
                location = "Недоступно"
            signals.ip_location_updated.emit(ip, location)
            
        thread = threading.Thread(target=worker, daemon=True)
        thread.start()
        
    def update_ip_location_labels(self, ip, location):
        self.ip_label.setText(f"IP: {ip}")
        self.location_label.setText(f"Локация: {location}")
        
    def scan_devices_async(self):
        def worker():
            global devices_by_model
            devices_by_model.clear()
            try:
                result = subprocess.run(["adb", "devices", "-l"], 
                                      capture_output=True, text=True, check=False)
                output = result.stdout.strip().splitlines()
                for line in output[1:]:
                    line = line.strip()
                    if not line or "offline" in line or "unauthorized" in line or "unknown" in line:
                        continue
                    parts = line.split()
                    serial = parts[0]
                    model = None
                    for p in parts:
                        if p.startswith("model:"):
                            model = p.split(":", 1)[1]
                            break
                    if not model:
                        model = "UnknownModel"
                    devices_by_model[model] = serial
                signals.log_message.emit(f"Устройства обновлены: {devices_by_model}", "info")
            except Exception as e:
                signals.log_message.emit(f"Ошибка при сканировании устройств: {e}", "error")
            
            model_list = list(devices_by_model.keys())
            signals.device_scan_completed.emit(model_list)
            
        thread = threading.Thread(target=worker, daemon=True)
        thread.start()
        
    def update_device_list(self, model_list):
        current_selection = self.load_last_model()
        self.device_combobox.clear()
        
        if model_list:
            self.device_combobox.addItems(model_list)
            if current_selection in model_list:
                self.device_combobox.setCurrentText(current_selection)
        else:
            self.device_combobox.addItem("Нет подключённых устройств")
            
    def refresh_wifi_async(self):
        def worker():
            global available_wifi_networks
            available_wifi_networks = get_available_networks()
            current_ssid = get_connected_wifi()
            signals.wifi_scan_completed.emit(available_wifi_networks, current_ssid)
            
        thread = threading.Thread(target=worker, daemon=True)
        thread.start()
        
    def update_wifi_list(self, networks, current_ssid):
        self.wifi_combobox.clear()
        if networks:
            self.wifi_combobox.addItems(networks)
            if current_ssid in networks:
                self.wifi_combobox.setCurrentText(current_ssid)
                
    def on_model_selected(self):
        model = self.device_combobox.currentText()
        self.save_last_model(model)
        
    def on_wifi_selected(self):
        global auto_paused_due_to_wifi
        selected = self.wifi_combobox.currentText()
        current_wifi = get_connected_wifi()
        
        if selected and selected != current_wifi:
            if is_processing and pause_event.is_set():
                pause_event.clear()
                auto_paused_due_to_wifi = True
                self.log_message("Процесс приостановлен автоматически (Wi-Fi mismatch).", "info")
            if not is_processing:
                self.start_button.setEnabled(False)
        else:
            if not is_processing:
                self.start_button.setEnabled(True)
            else:
                if auto_paused_due_to_wifi and not pause_event.is_set():
                    pause_event.set()
                    auto_paused_due_to_wifi = False
                    self.log_message("Процесс возобновлён автоматически (Wi-Fi выбран совпадает с текущей).", "info")
                    
    # Методы для работы с файлами настроек
    def get_limit_value(self):
        try:
            return int(self.limit_entry.text())
        except ValueError:
            return 0
            
    def save_last_limit(self):
        try:
            with open(last_limit_file, "w", encoding="utf-8") as f:
                f.write(self.limit_entry.text())
        except Exception as e:
            self.log_message(f"Ошибка при сохранении лимита: {e}", "error")
            
    def load_last_limit(self):
        try:
            with open(last_limit_file, "r", encoding="utf-8") as f:
                return f.read().strip()
        except Exception:
            return "0"
            
    def load_hide_browser_state(self):
        try:
            with open(hide_browser_state_file, "r", encoding="utf-8") as f:
                return f.read().strip().lower() == "true"
        except Exception:
            return False
            
    def load_run_scenario_start_state(self):
        try:
            with open(run_scenario_start_state_file, "r", encoding="utf-8") as f:
                return f.read().strip().lower() == "true"
        except Exception:
            return False
            
    def load_run_scenario_end_state(self):
        try:
            with open(run_scenario_end_state_file, "r", encoding="utf-8") as f:
                return f.read().strip().lower() == "true"
        except Exception:
            return False
            
    def save_last_model(self, model):
        try:
            with open(last_model_file, "w", encoding="utf-8") as f:
                f.write(model)
        except Exception as e:
            self.log_message(f"Ошибка при сохранении модели: {e}", "error")
            
    def load_last_model(self):
        try:
            with open(last_model_file, "r", encoding="utf-8") as f:
                return f.read().strip()
        except Exception:
            return ""
            
    # Методы для сохранения/загрузки состояния автопрокрутки
    def save_tokens_autoscroll_state(self):
        try:
            with open(tokens_autoscroll_state_file, "w", encoding="utf-8") as f:
                f.write(str(self.tokens_autoscroll_enabled).lower())
        except Exception as e:
            self.log_message(f"Ошибка при сохранении состояния автопрокрутки токенов: {e}", "error")
            
    def load_tokens_autoscroll_state(self):
        try:
            with open(tokens_autoscroll_state_file, "r", encoding="utf-8") as f:
                return f.read().strip().lower() == "true"
        except Exception:
            return True  # По умолчанию включено
            
    def save_failed_autoscroll_state(self):
        try:
            with open(failed_autoscroll_state_file, "w", encoding="utf-8") as f:
                f.write(str(self.failed_autoscroll_enabled).lower())
        except Exception as e:
            self.log_message(f"Ошибка при сохранении состояния автопрокрутки неуспешных логинов: {e}", "error")
            
    def load_failed_autoscroll_state(self):
        try:
            with open(failed_autoscroll_state_file, "r", encoding="utf-8") as f:
                return f.read().strip().lower() == "true"
        except Exception:
            return True  # По умолчанию включено
            
    # Методы Selenium и обработки аккаунтов
    def open_browser(self, login, password):
        global successful_attempts, failed_attempts, batch_success_count
        global invalid_login_count, captcha_count, token_not_found_count
        global timeout_count, element_not_found_count, unexpected_error_count
        
        start_time = time.time()
        signals.log_message.emit(f"Открытие браузера для: {login}", "info")
        
        options = Options()
        options.add_argument("--incognito")
        if self.hide_browser_check.isChecked():
            options.add_argument("--headless")
            options.add_argument("--disable-gpu")
            signals.log_message.emit("Скрытый режим браузера.", "info")
            
        service = Service(driver_path)
        driver = webdriver.Chrome(service=service, options=options)
        
        try:
            driver.get("https://vkhost.github.io/")
            signals.log_message.emit("Страница vkhost открыта.", "info")
            
            button = WebDriverWait(driver, 15).until(
                EC.element_to_be_clickable((By.CSS_SELECTOR, "button.btn[onclick='auth(6121396)']"))
            )
            button.click()
            signals.log_message.emit("Кнопка авторизации нажата.", "info")
            
            WebDriverWait(driver, 15).until(lambda d: len(d.window_handles) > 1)
            driver.switch_to.window(driver.window_handles[-1])
            signals.log_message.emit(f"Новая вкладка: {driver.current_url}", "info")
            
            WebDriverWait(driver, 15).until(
                lambda d: d.current_url.startswith("https://oauth.vk.com/authorize?")
            )
            signals.log_message.emit(f"Страница ВК: {driver.current_url}", "info")
            
            email_field = WebDriverWait(driver, 15).until(
                EC.presence_of_element_located((By.CSS_SELECTOR, "input[type='text'][name='email']"))
            )
            password_field = WebDriverWait(driver, 15).until(
                EC.presence_of_element_located((By.CSS_SELECTOR, "input[type='password'][name='pass']"))
            )
            
            email_field.send_keys(login)
            signals.log_message.emit("Логин введён.", "info")
            password_field.send_keys(password)
            signals.log_message.emit("Пароль введён.", "info")
            
            submit_button = WebDriverWait(driver, 15).until(
                EC.element_to_be_clickable((By.CSS_SELECTOR, "button.flat_button.oauth_button.button_wide[type='submit']"))
            )
            submit_button.click()
            signals.log_message.emit("Кнопка 'Войти' нажата.", "info")
            
            try:
                found_error = WebDriverWait(driver, 5).until(
                    EC.any_of(
                        EC.presence_of_element_located((By.CSS_SELECTOR, ".box_error")),
                        EC.presence_of_element_located((By.CSS_SELECTOR, ".oauth_captcha"))
                    )
                )
                
                error_class = found_error.get_attribute("class")
                if "box_error" in error_class:
                    error_text = "Невалидный логин или пароль."
                    invalid_login_count += 1
                elif "oauth_captcha" in error_class:
                    error_text = "Найдена капча"
                    captcha_count += 1
                else:
                    error_text = "Неизвестная ошибка"
                    unexpected_error_count += 1
                    
                failed_attempts += 1
                save_token_to_file(f"{error_text}: {login}", is_error=True)
                save_failed_login(login, password)
                append_full_result(login, password, error_text)
                signals.log_message.emit(f"Ошибка: {error_text}", "error")
                signals.append_token.emit(f"{error_text}: {login}")
                return
                
            except TimeoutException:
                pass
                
            allow_button = WebDriverWait(driver, 15).until(
                EC.element_to_be_clickable((By.CSS_SELECTOR, "button.flat_button[onclick='return allow(this);']"))
            )
            allow_button.click()
            signals.log_message.emit("Кнопка подтверждения нажата.", "info")
            
            WebDriverWait(driver, 15).until(
                lambda d: d.current_url.startswith("https://oauth.vk.com/blank.html#access_token=")
            )
            signals.log_message.emit(f"Страница с токеном: {driver.current_url}", "info")
            
            url = driver.current_url
            token_match = re.search(r"access_token=([^&]+)&expires_in", url)
            if token_match:
                token = token_match.group(1)
                save_token_to_file(token)
                append_full_result(login, password, token)
                successful_attempts += 1
                batch_success_count += 1
                signals.log_message.emit("Токен получен.", "success")
                
                current_limit = self.get_limit_value()
                if current_limit > 0 and batch_success_count >= current_limit:
                    self.run_flight_mode_scenario()
                    batch_success_count = 0
            else:
                failed_attempts += 1
                token_not_found_count += 1
                save_token_to_file(f"Токен не найден: {login}", is_error=True)
                save_failed_login(login, password)
                append_full_result(login, password, "Токен не найден")
                signals.log_message.emit("Ошибка: Токен не найден.", "error")
                signals.append_token.emit(f"Токен не найден: {login}")
                
        except TimeoutException:
            failed_attempts += 1
            timeout_count += 1
            save_token_to_file(f"Timeout: {login}", is_error=True)
            save_failed_login(login, password)
            append_full_result(login, password, "Timeout")
            signals.log_message.emit(f"Ошибка: Timeout. URL: {driver.current_url}", "error")
            signals.append_token.emit(f"Timeout: {login}")
            
        except NoSuchElementException:
            failed_attempts += 1
            element_not_found_count += 1
            save_token_to_file(f"Элемент не найден: {login}", is_error=True)
            save_failed_login(login, password)
            append_full_result(login, password, "Элемент не найден")
            signals.log_message.emit("Ошибка: Элемент не найден.", "error")
            signals.append_token.emit(f"Элемент не найден: {login}")
            
        except Exception as e:
            failed_attempts += 1
            unexpected_error_count += 1
            save_token_to_file(f"{str(e)}: {login}", is_error=True)
            save_failed_login(login, password)
            append_full_result(login, password, f"Ошибка: {e}")
            signals.log_message.emit(f"Неожиданная ошибка: {e}", "error")
            signals.append_token.emit(f"Неожиданная ошибка: {login}")
            
        finally:
            driver.quit()
            signals.log_message.emit("Браузер закрыт.", "info")
            signals.update_labels.emit()
            end_time = time.time()
            processing_time = end_time - start_time
            processing_time_formatted = format_time(processing_time)
            signals.log_message.emit(f"Обработка аккаунта {login} завершена за {processing_time_formatted}.", "info")
            
    def run_flight_mode_scenario(self):
        chosen_model = self.device_combobox.currentText()
        if not chosen_model:
            signals.log_message.emit("Не выбрана модель для сценария.", "error")
            return
            
        serial = devices_by_model.get(chosen_model)
        if not serial:
            signals.log_message.emit(f"Не найден serial для '{chosen_model}'.", "error")
            return
            
        try:
            signals.log_message.emit(f"Запуск сценария на '{chosen_model}'.", "info")
            d = u2.connect(serial)
            signals.log_message.emit(f"Устройство: {d.device_info}", "info")
            
            subprocess.run(["adb", "-s", serial, "shell", "am", "start", "-a", "android.settings.AIRPLANE_MODE_SETTINGS"])
            time.sleep(0.3)
            
            switch_element = d(resourceId="android:id/switch_widget")
            switch_element.click_exists(timeout=3)
            time.sleep(0.3)
            switch_element.click_exists(timeout=3)
            time.sleep(0.5)
            
            d.app_start("com.android.settings", ".TetherSettings")
            time.sleep(0.3)
            if d(resourceId="com.android.settings:id/recycler_view").child(index=0).exists(timeout=2):
                d(resourceId="com.android.settings:id/recycler_view").child(index=0).click()
                time.sleep(0.3)
                
            for _ in range(3):
                d.press("back")
                time.sleep(0.2)
                
            signals.log_message.emit("Ожидание Wi-Fi на ПК...", "info")
            while not is_connected():
                time.sleep(0.3)
            signals.log_message.emit("Wi-Fi подключен.", "info")
            time.sleep(1)
            
        except Exception as e:
            signals.log_message.emit(f"Ошибка сценария: {e}", "error")

# Вспомогательные функции
def append_full_result(login, password, result):
    all_results.append((login, password, result))

def add_token_separator():
    try:
        with file_lock:
            with open(tokens_file, "a", encoding="utf-8") as f:
                now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
                separator = f"\n{'='*30} {now} {'='*30}\n"
                f.write(separator)
    except Exception as e:
        signals.log_message.emit(f"Ошибка при добавлении разделителя: {e}", "error")

def save_token_to_file(token, is_error=False):
    try:
        with file_lock:
            with open(tokens_file, "a", encoding='utf-8') as file:
                if is_error:
                    file.write(f"Ошибка: {token}\n")
                else:
                    file.write(token + "\n")
        signals.log_message.emit(f"{'Ошибка' if is_error else 'Токен'} сохранён: {tokens_file}", "info")
        if not is_error:
            signals.append_token.emit(token)
    except Exception as e:
        signals.log_message.emit(f"Ошибка сохранения токена: {e}", "error")

def save_failed_login(login, password):
    try:
        with file_lock:
            with open(failed_logins_file, "a", encoding='utf-8') as file:
                file.write(f"{login}:{password}\n")
        signals.log_message.emit(f"Неуспешный логин сохранён: {failed_logins_file}", "info")
        signals.append_failed_login.emit(login, password)
    except Exception as e:
        signals.log_message.emit(f"Ошибка сохранения логина: {e}", "error")

def read_login_passwords():
    if not os.path.exists(login_pass_file):
        signals.log_message.emit(f"Файл не найден: {login_pass_file}", "error")
        return []
    try:
        with open(login_pass_file, "r", encoding='utf-8') as file:
            accounts = [line.strip().split(":", 1) for line in file if line.strip()]
        return accounts
    except Exception as e:
        signals.log_message.emit(f"Ошибка чтения файла: {e}", "error")
        return []

def is_connected():
    try:
        socket.create_connection(("8.8.8.8", 53), timeout=2)
        return True
    except OSError:
        return False

def get_connected_wifi():
    try:
        output = subprocess.check_output("netsh wlan show interfaces", shell=True, encoding="utf-8")
        for line in output.splitlines():
            if "SSID" in line and "BSSID" not in line:
                parts = line.split(":", 1)
                if len(parts) > 1:
                    ssid = parts[1].strip()
                    return ssid if ssid else "Нет подключения"
        return "Нет подключения"
    except Exception as e:
        return f"Ошибка: {e}"

def get_available_networks():
    networks = []
    try:
        output = subprocess.check_output("netsh wlan show networks", shell=True, encoding="utf-8")
        for line in output.splitlines():
            if "SSID" in line and ":" in line:
                parts = line.split(":", 1)
                if len(parts) > 1:
                    ssid = parts[1].strip()
                    if ssid and ssid not in networks:
                        networks.append(ssid)
    except Exception as e:
        signals.log_message.emit(f"Ошибка при получении сетей: {e}", "error")
    return networks

def get_external_ip():
    try:
        response = requests.get('https://api.ipify.org', timeout=5)
        response.raise_for_status()
        return response.text.strip()
    except requests.RequestException:
        return "Недоступно"

def get_location_by_ip(ip):
    try:
        response = requests.get(f'https://ipinfo.io/{ip}/json', timeout=5)
        response.raise_for_status()
        data = response.json()
        city = data.get('city', 'Неизвестно')
        region = data.get('region', 'Неизвестно')
        country = data.get('country', 'Неизвестно')
        return f"{city}, {region}, {country}"
    except requests.RequestException:
        return "Недоступно"

def main():
    app = QApplication(sys.argv)
    
    # Установка стиля приложения
    app.setStyle('Fusion')
    
    window = MainWindow()
    window.show()
    
    sys.exit(app.exec_())

if __name__ == "__main__":
    main()
